#ifndef SDK_OHOS_OHOS_PEER_CONNECTION_H_
#define SDK_OHOS_OHOS_PEER_CONNECTION_H_

#include <memory>
#include <string>
#include <vector>
#include "ohos_peer_connection_factory.h"
#include "api/ohos_media_stream_interface.h"
#include "api/peer_connection_interface.h"
#include "ohos_media_constraints.h"
#include "ohos_rtp_sender.h"
#include "ohos_rtp_receiver.h"
#include "ohos_rtp_transceiver.h"
#include "ohos_rtp_transceiver_init.h"
#include "api/ohos_data_channel_interface.h"

namespace ohoswebrtc {

class OHOSPeerConnectionDelegateAdapter : public webrtc::PeerConnectionObserver {
 public:
  OHOSPeerConnectionDelegateAdapter() {}
  virtual ~OHOSPeerConnectionDelegateAdapter();

  void RegisterPeerConnectionObserver(OHOSPeerConnectionObserver *observer, rtc::scoped_refptr<OHOSPeerConnectionFactoryInterface> peer_connection_factory);

  void UnRegisterPeerConnectionObserver();

  void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override;

  void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;

  void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;

  void OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) override;

  void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override;

  void OnRenegotiationNeeded() override;

  void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override;

  void OnStandardizedIceConnectionChange(
      webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
      
  void OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state) override;

  void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override;

  void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;

  void OnIceCandidateError(const std::string &address,
                           int port,
                           const std::string &url,
                           int error_code,
                           const std::string &error_text) override;

  void OnIceCandidatesRemoved(const std::vector<cricket::Candidate> &candidates) override;

  void OnIceSelectedCandidatePairChanged(const cricket::CandidatePairChangeEvent &event) override;

  void OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
                  const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) override;

  void OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override;

  private:
    OHOSPeerConnectionObserver* peer_connection_observer_;
    rtc::scoped_refptr<OHOSPeerConnectionFactoryInterface> peer_connection_factory_;
};

class OHOSPeerConnection : public OHOSPeerConnectionInterface {
  public:
    
    OHOSPeerConnection(webrtc::PeerConnectionInterface::RTCConfiguration &configuration,
                       rtc::scoped_refptr<OHOSMediaConstraintsInterface> constraints,
                       OHOSPeerConnectionObserver *observer,
                       rtc::scoped_refptr<OHOSPeerConnectionFactoryInterface> peer_connection_factory);
                       
    virtual ~OHOSPeerConnection();

    /** Provide a observer to peer connection callbacks */
    void RegisterPeerConnectionObserver(OHOSPeerConnectionObserver *observer) override;

    void UnRegisterPeerConnectionObserver() override;

    /** Provide a remote candidate to the ICE Agent. */
    void AddIceCandidate(const webrtc::IceCandidateInterface* candidate) override;

    void AddIceCandidate(const std::string sdp, int sdp_mline_index, const std::string sdp_mid) override;
    /** Remove a group of remote candidates from the ICE Agent. */
    void RemoveIceCandidate(const webrtc::IceCandidateInterface* candidate) override;

    /** Sets the PeerConnection's global configuration to `configuration`.
     *  Any changes to STUN/TURN servers or ICE candidate policy will affect the
     *  next gathering phase, and cause the next call to createOffer to generate
     *  new ICE credentials. Note that the BUNDLE and RTCP-multiplexing policies
     *  cannot be changed with this method.
     */
    void SetConfiguration(const webrtc::PeerConnectionInterface::RTCConfiguration& configuration) override;

    /** Terminate all media and close the transport. */
    void Close() override;

    /** Add a new media stream to be sent on this peer connection.
     *  This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use
     *  addTrack instead.
     */
    bool AddStream(rtc::scoped_refptr<OHOSMediaStreamInterface> stream) override;

    /** Remove the given media stream from this peer connection.
     *  This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use
     *  removeTrack instead.
     */
    void RemoveStream(rtc::scoped_refptr<OHOSMediaStreamInterface> stream) override;

    /** Add a new media stream track to be sent on this peer connection, and return
     *  the newly created OHOSRTCRtpSender. The OHOSRTCRtpSender will be
     * associated with the streams specified in the `streamIds` list.
     *
     *  Errors: If an error occurs, returns nil. An error can occur if:
     *  - A sender already exists for the track.
     *  - The peer connection is closed.
     */
    rtc::scoped_refptr<OHOSRtpSenderInterface> AddTrack(
      rtc::scoped_refptr<OHOSMediaTrackInterface> track, const std::vector<std::string> streamIds) override;

    /** With PlanB semantics, removes an OHOSRTCRtpSender from this peer connection.
     *
     *  With UnifiedPlan semantics, sets sender's track to null and removes the
     *  send component from the associated OHOSRTCRtpTransceiver's direction.
     *
     *  Returns YES on success.
     */
    bool RemoveTrack(rtc::scoped_refptr<OHOSRtpSenderInterface> sender) override;

    /** Adds a transceiver with a sender set to transmit the given track. The kind
     *  of the transceiver (and sender/receiver) will be derived from the kind of
     *  the track.
     */
    rtc::scoped_refptr<OHOSRtpTransceiverInterface> AddTransceiver(
      rtc::scoped_refptr<OHOSMediaTrackInterface> track) override;

    rtc::scoped_refptr<OHOSRtpTransceiverInterface> AddTransceiver(
      rtc::scoped_refptr<OHOSMediaTrackInterface> track,
      const webrtc::RtpTransceiverInit &init) override;

    /** Adds a transceiver with the given kind. Can either be MediaTypeAudio
     *  or MediaTypeVideo.
     */
    rtc::scoped_refptr<OHOSRtpTransceiverInterface> AddTransceiver(
      cricket::MediaType media_type) override;

    rtc::scoped_refptr<OHOSRtpTransceiverInterface> AddTransceiver(
      cricket::MediaType media_type, const webrtc::RtpTransceiverInit &init) override;
    
    /** Create a new offer.
     *  The CreateSessionDescriptionSuccess or CreateSessionDescriptionFailure 
     *  callback will be called when done.
     */
    void CreateOffer(rtc::scoped_refptr<OHOSMediaConstraintsInterface> constraints,
                     CreateSessionDescriptionSuccess success,
                     CreateSessionDescriptionFailure failure) override;
    /** Create a new offer.
     *  The CreateSessionDescriptionObserver callback will be called when done.
     */
    void CreateOffer(webrtc::CreateSessionDescriptionObserver* observer,
                     rtc::scoped_refptr<OHOSMediaConstraintsInterface> constraints) override;
    
    /** Create a new answer.
     *  The success or failure callback will be called when done.
     */
    void CreateAnswer(rtc::scoped_refptr<OHOSMediaConstraintsInterface> constraints,
                      CreateSessionDescriptionSuccess success,
                      CreateSessionDescriptionFailure failure) override;

    /** Create a new answer.
     *  The CreateSessionDescriptionObserver callback will be called when done.
     */
    void CreateAnswer(webrtc::CreateSessionDescriptionObserver* observer,
                      rtc::scoped_refptr<OHOSMediaConstraintsInterface> constraints) override;

    /** Sets the local session description.
     *  The OnSdpDescriptionCallback callback will be called when done.
     */
    void SetLocalDescription(OnSdpDescriptionCallback callback) override;

    void SetLocalDescription(rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface> observer) override;
    
    /** Sets the local session description.
     *  The observer is invoked as soon as the operation completes, which could be
     *  before or after the SetLocalDescription() method has exited
     */
    void SetLocalDescription(std::unique_ptr<webrtc::SessionDescriptionInterface> sdp_desc,
                             OnSdpDescriptionCallback callback) override;

    void SetLocalDescription(std::unique_ptr<webrtc::SessionDescriptionInterface> sdp_desc,
                             rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface> observer) override;
    
    /** Sets the local session description.
     *  The OnSdpDescriptionCallback callback will be called when done.
     */
    void SetLocalDescription(const std::string sdp_desc,
                             webrtc::SdpType sdp_type,
                             OnSdpDescriptionCallback callback) override;

    void SetLocalDescription(const std::string sdp_desc,
                             webrtc::SdpType sdp_type,
                             rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface> observer) override;
    
    void SetRemoteDescription(std::unique_ptr<webrtc::SessionDescriptionInterface> sdp_desc,
                              OnSdpDescriptionCallback callback) override;
    
    /** Sets the local session description.
     *  The observer callback will be called when done.
     */
    void SetRemoteDescription(std::unique_ptr<webrtc::SessionDescriptionInterface> sdp_desc,
                              rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface> observer) override;

    void SetRemoteDescription(const std::string sdp_desc,
                              webrtc::SdpType sdp_type,
                              OnSdpDescriptionCallback callback) override;

    void SetRemoteDescription(const std::string sdp_desc,
                              webrtc::SdpType sdp_type,
                              rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface> observer) override;

    /** 
     * The spec-compliant GetStats() API. This correspond to the promise-based
     * version of getStats() in JavaScript. Implementation status is described in
     * api/stats/rtcstats_objects.h
     */
    void GetStats(OnStatsCollectorCompletion completion) override;
    
    /** 
     * return OHOSRtpSenders
     */
    std::vector<rtc::scoped_refptr<OHOSRtpSenderInterface>> senders() override;
    
    /** 
     * return OHOSRtpSenders
     */
    std::vector<rtc::scoped_refptr<OHOSRtpTransceiverInterface>> transceivers() override;

    /** 
     * return OHOSRtpReceivers
     */
    std::vector<rtc::scoped_refptr<OHOSRtpReceiverInterface>> receivers() override;
   
    /** 
     * return OHOSMediaStream
     */
    std::vector<rtc::scoped_refptr<OHOSMediaStreamInterface>> local_streams() override {
      return local_streams_;
    }

    /** Returns the current SignalingState. */
    webrtc::PeerConnectionInterface::SignalingState signaling_state() override;

    /** Returns an aggregate state of all ICE *and* DTLS transports.
     *  This is left in place to avoid breaking native clients who expect our old,nonstandard behavior.
     */
    webrtc::PeerConnectionInterface::IceConnectionState ice_connection_state() override;

    /** Returns an aggregated state of all ICE transports. */
    webrtc::PeerConnectionInterface::IceConnectionState standardized_ice_connection_state() override;

    /** Returns an aggregated state of all ICE and DTLS transports. */
    webrtc::PeerConnectionInterface::PeerConnectionState peer_connection_state() override;
    webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state() override;
  
    /** Returns the current state of canTrickleIceCandidates per. */
    absl::optional<bool> can_trickle_ice_candidates() override;
  
    /** When a resource is overused, the PeerConnection will try to reduce the load on the sysem. 
     *  for example by reducing the resolution or frame rate of 
     * encoded streams. The Resource API allows injecting platform-specific usage 
     * measurements. The conditions to trigger kOveruse or kUnderuse are up to the
     * implementation
     */
    void AddAdaptationResource(rtc::scoped_refptr<webrtc::Resource> resource) override;

  private:

    std::vector<rtc::scoped_refptr<OHOSMediaStreamInterface>> local_streams_;

    rtc::scoped_refptr<OHOSPeerConnectionFactoryInterface> peer_connection_factory_;

    rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;

    std::unique_ptr<OHOSPeerConnectionDelegateAdapter> adapter_observer_;

    rtc::scoped_refptr<OHOSMediaConstraintsInterface> constraints_;
  
    webrtc::Mutex pc_mutex_;
    
};

}
#endif